home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / human interface toolbox / edittextcdev / editcdev.c next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  9.7 KB  |  279 lines

  1. /*
  2.     File:        EditCdev.c
  3.  
  4.     Contains:    EditCdev is a sample Control Panel device (cdev) that 
  5.                 demonstrates the usage of the edit-related messages.  
  6.                 EditCdev demonstrates how to implement an editText item
  7.                 in a Control Panel Device.  It utilizes the new undo, cut, copy,
  8.                 paste, and delete messages that are sent to cdevs in
  9.                 response to user menu selections.
  10.     
  11.                 It is comprised of two editText items that can be edited 
  12.                 and moved between via the mouse or tab key.
  13.  
  14.     Written by:     
  15.  
  16.     Copyright:    Copyright © 1988-1999 by Apple Computer, Inc., All Rights Reserved.
  17.  
  18.                 You may incorporate this Apple sample source code into your program(s) without
  19.                 restriction. This Apple sample source code has been provided "AS IS" and the
  20.                 responsibility for its operation is yours. You are not permitted to redistribute
  21.                 this Apple sample source code as "Apple sample source code" after having made
  22.                 changes. If you're going to re-distribute the source, we require that you make
  23.                 it clear in the source that the code was descended from Apple sample source
  24.                 code, but that you've made changes.
  25.  
  26.     Change History (most recent first):
  27.                 8/5/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  28.                 
  29.  
  30. */
  31. #include <Sound.h>
  32. #include <Types.h>
  33. #include <Memory.h>
  34. #include <Quickdraw.h>
  35. #include <TextEdit.h>
  36. #include <Dialogs.h>
  37. #include <Events.h>
  38. #include <Devices.h>
  39. #include <Scrap.h>
  40. #include <Packages.h>
  41. #include <TextEdit.h>
  42. #include <TextUtils.h>
  43.  
  44. /* Constants */
  45. #define    textItm        1            /* first editText item in cdev */
  46. #define countItm    4            /* first staticText item for displaying character count */
  47.  
  48. #define    undoDev        9            /* cdev edit messages */
  49. #define    cutDev        10
  50. #define    copyDev        11
  51. #define    pasteDev    12
  52. #define    clearDev    13
  53.  
  54. #define maxLength    50            /* maximum # of characters in each textEdit field < 32K */
  55.  
  56. #define delete        0x08        /* character codes for various keys */
  57. #define tab            0x09
  58. #define leftArrow    0x1c
  59. #define rightArrow    0x1d
  60. #define upArrow        0x1e
  61. #define downArrow    0x1f
  62.  
  63. /*
  64.  *  TYPES:  Storage for CDEV - All permanent CDEV storage must be referred to by a single
  65.  *            handle, so put all permanent variables in a CDEVRec.
  66.  */
  67. typedef struct CDEVRec
  68. {
  69.     Boolean needUpdate;
  70. } CDEVRec, *CDEVPtr, **CDEVHnd;
  71.  
  72.  
  73. /*
  74.  *  PROTOTYPES
  75.  */
  76. void DoEditCommand (short message, DialogPtr CPDialog);
  77. pascal CDEVHnd main(short message, short item, short numItems, short CPanelID,
  78.          EventRecord *theEvent, CDEVHnd cdevStorage, DialogPtr CPDialog);
  79. void UpdateCharCount(DialogPtr CPDialog);
  80.  
  81.  
  82. /* This is the main dispatcher. It must be the first code in the cdev.
  83.  * EditCdev's dispatcher responds only to the following messages from
  84.  * the Control Panel:
  85.  *    
  86.  *        macDev        - To indicate what machines it is available on.
  87.  *        nulDev        - To check if the character count items need to be updated.
  88.  *        initDev        - To set up some temporary storage and get the caret started.
  89.  *        keyEvtDev    - To check for an edit command and do the appropriate action.
  90.  *        cutDev        - To cut the current selection.
  91.  *        copyDev        - To copy the current selection.
  92.  *        pasteDev    - To paste the contents of the clipboard.
  93.  *        clearDev    - To delete the current selection.
  94.  *
  95.  * The Dialog Manager's services are used to handle entry of text, selection
  96.  * of text, editing of text, and moving between the editText items via the
  97.  * tab key. Since the Dialog Manager handles the selection of text, we do not
  98.  * have to be concerned with hitDev messages for the editText items. The only
  99.  * things we have to take care of are calling the Dialog Manager editing
  100.  * routines in response to an edit command, and getting the caret to show up
  101.  * at the beginning. In response to an edit command that was the result of
  102.  * a command-key equivalent, we must also eliminate the event so that it does
  103.  * not get processed as a keyDown by the Dialog Manager. Otherwise, an 'x'
  104.  * would show up in the editText item when the user did a command-x to cut
  105.  * the text.
  106.  *        Also, we must be aware that the dialog manager does not keep track
  107.  * of the length of the characters typed or pasted into the textEdit items.
  108.  * Since the maximum number of characters that may be contained in a single
  109.  * textEdit item is 32K, we must make sure that the user does not enter more
  110.  * than some maximum number of characters.
  111.  */
  112.  
  113.  
  114. pascal CDEVHnd main(short message, short item, short numItems, short CPanelID,
  115.                        EventRecord *theEvent, CDEVHnd cdevStorage, DialogPtr CPDialog)
  116. {
  117. #pragma unused (item, CPanelID)        /* unused formal parameters */
  118.  
  119.     char         tempChar;
  120.     TEHandle    myTEHandle;    /* handle to the current textEdit record */
  121.     short        selLength;    /* length of current selection */
  122.  
  123.     if (message == macDev) return((CDEVHnd) 1);                /* we work on every machine */
  124.     else if (cdevStorage != nil) {
  125.         switch (message) {
  126.             case initDev:                                    /* initialize cdev */
  127.                 cdevStorage = (CDEVHnd)NewHandle(sizeof(CDEVRec));    /* create private storage */
  128.                 SelectDialogItemText(CPDialog, numItems + textItm, 0, 999); /* make caret show up */
  129.                 break;
  130.                 
  131.             case nulDev:
  132.                 if ((**cdevStorage).needUpdate)        /* character count need updating? */
  133.                 {
  134.                     UpdateCharCount(CPDialog);
  135.                     (**cdevStorage).needUpdate = false;
  136.                 }
  137.                 break;
  138.  
  139.             case hitDev:                                    /* handle hit on item */
  140.             case closeDev:                                    /* clean up and dispose */
  141.             case updateDev:                                    /* handle any update drawing */
  142.             case activDev:                                    /* activate any needed items */
  143.             case deactivDev:                                /* deactivate any needed items */
  144.                 break;
  145.                 
  146.             case keyEvtDev:                                    /* respond to keydown */
  147.                 tempChar = theEvent->message & charCodeMask;/* get the character, and check */
  148.                 if (theEvent->modifiers & cmdKey)            /*  status of command key */
  149.                 {
  150.                     message = nulDev;                        /* start with no message */
  151.                     theEvent->what = nullEvent;                /* and empty event type */
  152.                     
  153.                     switch (tempChar)                        /* set appropriate message */
  154.                     {    
  155.                         case 'X':
  156.                         case 'x':
  157.                             message = cutDev;
  158.                             break;
  159.                         case 'C':
  160.                         case 'c':
  161.                             message = copyDev;
  162.                             break;
  163.                         case 'V':
  164.                         case 'v':
  165.                             message = pasteDev;
  166.                             break;
  167.                     }
  168.                     DoEditCommand(message, CPDialog);        /* Let edit command handler take it */
  169.                 }
  170.                 else    /* not a command key */
  171.                 {
  172.                     /*   We need to update the character count, but only after textEdit has    */
  173.                     /* a chance to deal with it.  Set a flag so that during the next nullEvent */
  174.                     /* we will process the character count update.  If we call UpdateCharCount */
  175.                     /* now, we will display the incorrect count.                               */
  176.                     /*   Also, we must make sure that we are not exceeding our character limit */
  177.                     /* with this character.  (unless it is a tab or backspace, that's OK)       */
  178.                     
  179.                     (**cdevStorage).needUpdate = true;        /* update count during next nulDev */
  180.                     
  181.                     myTEHandle = ((DialogPeek)CPDialog)->textH;
  182.                     selLength = ((**myTEHandle).selEnd-(**myTEHandle).selStart);
  183.  
  184.                     if ( ((**myTEHandle).teLength>=maxLength+selLength) &&
  185.                             (tempChar!=delete) && (tempChar!=tab) &&
  186.                             (tempChar!=leftArrow) && (tempChar!=rightArrow) &&
  187.                             (tempChar!=upArrow) && (tempChar!=downArrow) )
  188.                     {
  189.                         theEvent->what = nullEvent;    /* trash character (textEdit never sees it) */
  190.                         SysBeep(1);
  191.                     }
  192.                 }
  193.                 break;
  194.                 
  195.             case macDev:
  196.             case undoDev:
  197.                 break;
  198.                 
  199.             case cutDev:
  200.             case copyDev:
  201.             case pasteDev:
  202.             case clearDev:
  203.                 DoEditCommand(message, CPDialog);        /* respond to edit command */
  204.                 break;
  205.         }
  206.  
  207.         return (cdevStorage);
  208.     }  /* cdevStorage != nil */
  209.     
  210.     return (nil);    /* if cdevStorage = NIL then ControlPanel will put up memory error. */
  211. }
  212.  
  213. /* Call the appropriate Dialog Manager routine to handle an edit command for */
  214. /* an editText item. It will do *ALMOST* all the work regarding the TEScrap. */
  215. void DoEditCommand(short message, DialogPtr CPDialog)
  216. {
  217.     TEHandle    myTEHandle;        /* Handle to current textEdit record */
  218.     long        scrapLength;    /* length of textEdit scrap */
  219.     long        freeSpace;        /* amount of space before character limit */
  220.     short        selLength;        /* length of current selection */
  221.  
  222.     myTEHandle = ((DialogPeek)CPDialog)->textH;
  223.  
  224.     switch (message)
  225.     {
  226.     case cutDev:
  227.         DialogCut(CPDialog);
  228.         break;
  229.     case copyDev:
  230.         DialogCopy(CPDialog);
  231.         break;
  232.     case pasteDev:
  233.         /* Since the maximum number of characters that a textEdit structure can   */
  234.         /* handle is 32K, and the dialog manager doesn't check for overflow when  */
  235.         /* pasting, we must check for ourselves and only paste as many characters */
  236.         /* as we have room for. */
  237.         scrapLength = TEGetScrapLength();
  238.         selLength = ((**myTEHandle).selEnd-(**myTEHandle).selStart);
  239.         freeSpace = (long)(maxLength-(**myTEHandle).teLength)+selLength;
  240.         if (freeSpace>=scrapLength)    /* enough room for paste? */
  241.             DialogPaste(CPDialog);
  242.         else                        /* not enough room for paste */
  243.         {
  244.             SysBeep(1);
  245.             if (freeSpace>0)        /* any room for paste? */
  246.             {
  247.                 TESetScrapLength(freeSpace);    /* only paste as many characters as free */
  248.                 DialogPaste(CPDialog);
  249.                 TESetScrapLength(scrapLength);    /* restore textEdit scrap length */
  250.             }
  251.         }
  252.         break;
  253.     case clearDev:
  254.         DialogDelete(CPDialog);
  255.         break;
  256.     }
  257.     UpdateCharCount(CPDialog);
  258. }
  259.  
  260. /* Examine the appropriate structures to determine the number of characters in the */
  261. /* acvive TERecord and display in the corresponding static text item. */
  262. void UpdateCharCount(DialogPtr CPDialog)
  263. {
  264.     TEHandle    myTEHandle;
  265.     short        itemType;
  266.     Handle        itemHandle;
  267.     Rect        itemRect;
  268.     Str255        text;
  269.     short        editItem;
  270.  
  271.     myTEHandle = ((DialogPeek)CPDialog)->textH;            /* get handle to TERecord */
  272.     HLock((Handle)myTEHandle);
  273.     NumToString((long)((**myTEHandle).teLength), text);    /* get length of text */
  274.     HUnlock((Handle)myTEHandle);
  275.     editItem=countItm+((DialogPeek)CPDialog)->editField; /* calculate which item to change */
  276.     GetDialogItem(CPDialog, editItem, &itemType, &itemHandle, &itemRect);
  277.     SetDialogItemText(itemHandle, text);                            /* change text item contents */
  278. }
  279.